/* *
 * Created by yihua on 2021/8/18
 *
 * 调用pg接口的辅助工具，原生版 （但有使用ES6的map和set）
 * 改自朱继昌的版本
 * */

var ApiQueriesDefaultTemplate = {
  'like': '*%v*',
  'ilike': '*%v*',
  'in': '(%v)',
};

pgApiUtils = function(baseUrl) {
  // 实例化方法 pgApiUtils() 实际上是调用了其拓展的原型方法 pgApiUtils.fn.init
  return new pgApiUtils.fn.init(baseUrl);
}

// pgApiUtils.prototype 即是 pgApiUtils 的原型，挂载在上面的方法，即可让所有生成的 pgApiUtils 对象使用
pgApiUtils.fn = pgApiUtils.prototype = {
  // 实例化化方法，这个方法可以称作 pgApiUtils 对象构造器
  init: function(baseUrl) {
    this.baseUrl = baseUrl;
    this.requestUrl = '';
    this.queries = {};
    this.param = new Map();
    this.string = '';
    this.prefixNot = false;
    return this;
  },

  setRequestUrl:function(requestUrl){
    this.requestUrl = requestUrl;
    return this
  },

  setQueries: function (queries) {
    for (let key in queries) {
      if (Object.prototype.toString.call(queries[key]) == "[object String]") {
        queries[key] = queries[key].replace(/(^\s*)|(\s*$)/g, "");
      }
    }
    this.queries = JSON.parse(JSON.stringify(queries));
    return this;
  },

  select : function () {
    var that = this;
    if (arguments.length > 0) {
      let set = that.param.get('select') || new Set();
      that.param.set('select', union(set, new Set(arguments)))
    }
    return this;
  },

  not: function () {
    this.prefixNot = true;
    return this;
  },

  order: function () {
    var that = this;
    if (arguments.length > 0) {
      let set = that.param.get('order') || new Set();
      that.param.set('order', union(set, new Set(arguments)))
    }
    return this;
  },

  _simpleOperator : function (operator, args) {
    var that = this;
    if (args.length > 0) {
      for(var key in args) {
        const [searchKey, queryKey, format] = args[key].split(':');
        const searchValue = that.queries[queryKey || searchKey];
        if (searchValue !== 0 && !searchValue) {
          return this;
        }
        let set = that.param.get(searchKey) || new Set();
        const template = format || ApiQueriesDefaultTemplate[operator] || '%v';
        if(!this.prefixNot){
          that.param.set(searchKey, union(set, new Set([`${operator}.${template.replace('%v', searchValue)}`])))
        }else{
          that.param.set(searchKey, union(set, new Set([`${'not.'+ operator }.${template.replace('%v', searchValue)}`])))
          this.prefixNot = false;
        }
      }
    }
    return this;
  },

  _simpleOperatorVal(operator, args) {
    var that = this;
    if (args.length > 0) {
      for(var key in args){
        const [searchKey, queryKey, format] = args[key].split(':');
        if (queryKey !== 0 && !queryKey) {
          return this;
        }
        let set = that.param.get(searchKey) || new Set();
        const template = format || ApiQueriesDefaultTemplate[operator] || '%v';

        if(!this.prefixNot){
          that.param.set(searchKey, union(set, new Set([`${operator}.${template.replace('%v', queryKey)}`] ) ))
        }else{
          that.param.set(searchKey, union(set, new Set([`${'not.'+ operator }${template.replace('%v', queryKey)}`] ) ))
          this.prefixNot = false;
        }
      }
    }
    return this;
  },

  eq : function () {
    return this._simpleOperator('eq', arguments);
  },

  neq : function () {
    return this._simpleOperator('neq', arguments);
  },

  like : function () {
    return this._simpleOperator('like', arguments);
  },

  ilike : function () {
    return this._simpleOperator('ilike', arguments);
  },

  is : function () {
    return this._simpleOperator('is', arguments);
  },

  cs : function () {
    return this._simpleOperator('cs', arguments);
  },

  cd : function () {
    return this._simpleOperator('cd', arguments);
  },

  in : function () {
    return this._simpleOperator('in', arguments);
  },

  gt : function () {
    return this._simpleOperator('gt', arguments);
  },

  gte : function () {
    return this._simpleOperator('gte', arguments);
  },

  lt : function () {
    return this._simpleOperator('lt', arguments);
  },

  lte : function () {
    return this._simpleOperator('lte', arguments);
  },

  eqVal : function () {
    return this._simpleOperatorVal('eq', arguments);
  },

  neqVal : function () {
    return this._simpleOperatorVal('neq', arguments);
  },

  likeVal : function () {
    return this._simpleOperatorVal('like', arguments);
  },

  ilikeVal : function () {
    return this._simpleOperatorVal('ilike', arguments);
  },

  isVal : function () {
    return this._simpleOperatorVal('is', arguments);
  },

  csVal : function () {
    return this._simpleOperatorVal('cs', arguments);
  },

  cdVal : function () {
    return this._simpleOperatorVal('cd', arguments);
  },

  inVal : function () {
    return this._simpleOperatorVal('in', arguments);
  },

  gtVal : function () {
    return this._simpleOperatorVal('gt', arguments);
  },

  gteVal : function () {
    return this._simpleOperatorVal('gte', arguments);
  },

  ltVal : function () {
    return this._simpleOperatorVal('lt', arguments);
  },

  lteVal : function () {
    return this._simpleOperatorVal('lte', arguments);
  },

  page : function(pageIndex, pageSize, total ) { // 最后一个参数是反序的总条数
    pageSize = pageSize || 10
    if(!total){
      this.param.set('offset', new Set([(pageIndex - 1) *  pageSize]))
    }else{
      // 最后一个参数是反序的总条数
      this.param.set('offset', new Set([(total % pageSize) + (pageIndex - 1) *  pageSize]))
    }
    this.param.set('limit', new Set([pageSize]))
    return this;
  },

  /* This method is often useful in-combination with $ where both functions are given the
  *  @param {countStart} 第一个参数不用算多少页了，offset的值
  *  @param {pageSize}
  *  @param {total} 最后一个参数是反序的开关 如果需要反序则会传值 如果总记录数是0 就不反序了，所以传总页数当开关
  **/
  pageItem : function(countStart, pageSize, total ) {  // 第一个参数不用算多少页了
    pageSize = pageSize || 10
    if(!total){
      this.param.set('offset', new Set([countStart]))
      this.param.set('limit', new Set([pageSize]))
    }else{
      // 最后一个参数是反序的总条数
      this.param.set('offset', new Set([ (total % pageSize) + (total - countStart) ]))
      let orderSet = this.param.get('order')
      if(orderSet.size>0){
        let setIter = orderSet.values();
        let orderString = setIter.next().value;
        if(orderString){
          let orderArr = orderString.split(',') || []
          let newOrderArr = [];
          for(let i=0;i<orderArr.length; i++){
            if(orderArr[i].indexOf('.desc')>-1){ newOrderArr.push(orderArr[i].replace('.desc',''))}else{newOrderArr.push(orderArr[i]+'.desc')}
          }
          let newOrderString = newOrderArr.join(',')
          this.param.set('order',new Set([newOrderString]))
        }
      }
      if(countStart === (total - total % pageSize) ){
        this.param.set('limit', new Set([total % pageSize]))
      }else{
        this.param.set('limit', new Set([pageSize]))
      }
    }



    return this;
  },

  toString: function () {
    let tempString = '';
    for (let [key, value] of this.param) {
      tempString += key + '=' + Array.from(value).join(',') + '&';
    }
    tempString = tempString.substring(0, tempString.length - 1)
    return this.baseUrl + '?' + this.requestUrl + tempString
  }
};

// 获取总页数
pgApiUtils.getTotal = function(request){
  var range = request.getResponseHeader('content-range')
  if (range) {
    const [, , , total] = /^(\d+)-(\d+)\/(\d+|\*)$/.exec(range) || [0, 0, 0, 0];
    return total || 0
  }else{
    return 0
  }
};

// 无new 引用的精华所在

pgApiUtils.fn.init.prototype = pgApiUtils.fn;

//pgApiUtils('/extend').setQueries({a:1}).page(1,10).toString()
function union(setA, setB) {
  let _union = new Set(setA);
  for (let elem of setB) {
    _union.add(elem);
  }
  return _union;
}


Date.prototype.format = function(fmt)
{ //author: meizz
  var o = {
    "M+" : this.getMonth()+1,                 //月份
    "d+" : this.getDate(),                    //日
    "h+" : this.getHours(),                   //小时
    "m+" : this.getMinutes(),                 //分
    "s+" : this.getSeconds(),                 //秒
    "q+" : Math.floor((this.getMonth()+3)/3), //季度
    "S"  : this.getMilliseconds()             //毫秒
  };
  if(/(y+)/.test(fmt))
    fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
  for(var k in o)
    if(new RegExp("("+ k +")").test(fmt))
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
  return fmt;
}
